package cn.kgc.filter;

import cn.hutool.json.JSONUtil;
import cn.kgc.grace.result.ResponseStatusEnum;
import cn.kgc.utils.ExcludeProperties;
import cn.kgc.utils.JwtUtil;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static cn.kgc.base.SystemConstant.*;

/**
 * @author wangyue
 * @version 1.0
 * 验证令牌是否正确
 */
@Component
public class SecurityJwtFilter implements GlobalFilter, Ordered {

    @Resource
    private ExcludeProperties excludeProperties;

    @Resource
    private JwtUtil jwtUtil;

    @Override
    public int getOrder() {
        return 0;
    }

    /**
     * 向请求头中添加新的属性名和属性值
     * @param exchange     请求
     * @param headerKey    请求头属性名
     * @param headerValue  请求头属性值
     */
    private ServerWebExchange setNewHeader(ServerWebExchange exchange, String headerKey,  String headerValue) {
        ServerHttpRequest newRequest = exchange.getRequest()
                .mutate()
                .header(headerKey, headerValue)
                .build();
        return exchange.mutate().request(newRequest).build();
    }

    /**
     * 返回令牌错误的信息
     */
    private Mono<Void> renderErrorMsg(ServerWebExchange exchange){
        ServerHttpResponse response = exchange.getResponse();
        Map<String,Object> result=new HashMap<>();
        //业务中的状态码是501
        result.put("status",ResponseStatusEnum.UN_LOGIN.status());
        result.put("msg",ResponseStatusEnum.UN_LOGIN.msg());
        result.put("data",null);
        result.put("success",false);
        //响应的状态码是500
        response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
        //返回的数据是json格式的数据
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        //数据的编码格式是utf-8
        DataBuffer wrap = response.bufferFactory()
                .wrap(JSONUtil.toJsonStr(result).getBytes(StandardCharsets.UTF_8));
        //返回响应的信息
        return response.writeWith(Mono.just(wrap));
    }

    /**
     * 路径匹配规则器
     */
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1 判断请求地址是否需要验证令牌 如果不需要直接放行
        //获得用户的请求地址
        String path = exchange.getRequest().getPath().toString();
        //不需要验证令牌的请求地址
        List<String> urls = excludeProperties.getUrls();
        //判断请求地址是否在不需要验证令牌的请求地址中
        if(urls.stream().anyMatch(url->antPathMatcher.match(url,path))){
            //如果在请求直接放行
            return chain.filter(exchange);
        }
        //2 从请求头中获得令牌,判断令牌是否正确
        String token= exchange.getRequest().getHeaders().getFirst(LOGIN_TOKEN);
        try {
            //如果令牌正确从令牌中获得登录的用户信息(用户的ID  登录的类型)
            String userId = jwtUtil.getUserId(token);
            String loginType = jwtUtil.getLoginType(token);
            //将用户信息添加到请求头中
            setNewHeader(exchange,HEADER_USER_ID,userId);
            setNewHeader(exchange,HEADER_LOGIN_TYPE,loginType);
        } catch (Exception e) {
            //3 如果令牌错误,返回错误信息
            //todo 系统错误日志信息的存储
            return renderErrorMsg(exchange);
        }
        //请求放行
        return chain.filter(exchange);
    }
}